﻿using System;
using System.Collections.Generic;
using System.Text;
using RouterControl.LocalDb;
using RouterControl.Whs;

namespace RouterControl.Service.DeviceSlaves
{
    [RouterSlave]
    public sealed class ConfigDataSlave : RouterSlave
    {
        private LocalDbConnector _db;
        private LocalDbConnector.DeviceInfo? _router;
        private CommonInternetGateway.ConnectionStatusValues? _lastConnectionStatus;

        public CommonInternetGateway.SummaryData? Config
        {
            get;
            private set;
        }

        public override void OnDataUpdated()
        {
            base.OnDataUpdated();

            // finalize
            this.Config = this.Router.Summary;
        }

        public override void OnRouterChanged(CommonInternetGateway newRouter)
        {
            base.OnRouterChanged(newRouter);

            // continue
            if (newRouter != null)
            {
                _router = _db.EnsureDevice(
                    newRouter.Device.UniqueDeviceName,
                    newRouter.Device.Type
                    );

                this.Config = newRouter.Summary;

                // track current status
                if (this.Config.HasValue && this.Config.Value.ConnectionStatus.HasValue)
                {
                    _db.AddOnlineStatusInfo(
                        _router.Value,
                        new LocalDbConnector.OnlineStatusInfo()
                        {
                            TimeStamp = DateTime.Now,
                            OldStatus = null,
                            NewStatus = this.Config.Value.ConnectionStatus.Value.ToString()
                        });

                    _lastConnectionStatus = this.Config.Value.ConnectionStatus;
                }

                // subscribe to status changes
                var ppp = newRouter.Device.GetServiceRecursive<UpnpOrg.WANPPPConnection1.IWANPPPConnection1>();

                if (ppp != null)
                {
                    ppp.OnConnectionStatusChanged += new StateVariableChangedDelegate<UpnpOrg.WANPPPConnection1.Types.ConnectionStatusValues>(ppp_OnConnectionStatusChanged);
                }

                var ip = newRouter.Device.GetServiceRecursive<UpnpOrg.WANIPConnection1.IWANIPConnection1>();

                if (ip != null)
                {
                    ip.OnConnectionStatusChanged += new StateVariableChangedDelegate<UpnpOrg.WANIPConnection1.Types.ConnectionStatusValues>(ip_OnConnectionStatusChanged);
                }
            }
            else
            {
                // clear status changes
                if (_lastConnectionStatus.HasValue)
                {
                    _db.AddOnlineStatusInfo(
                        _router.Value,
                        new LocalDbConnector.OnlineStatusInfo()
                        {
                            TimeStamp = DateTime.Now,
                            OldStatus = _lastConnectionStatus.Value.ToString(),
                            NewStatus = null
                        });
                }

                _lastConnectionStatus = null;

                // clear router
                _router = null;

                this.Config = null;
            }
        }

        private void ip_OnConnectionStatusChanged(RouterControl.IO.IDeviceService sender, StateVariableChangedEventArgs<UpnpOrg.WANIPConnection1.Types.ConnectionStatusValues> e)
        {
            var val = CommonInternetGateway.ToCommonInternetGateway(e.NewValue);

            if (val.HasValue)
                common_OnConnectionStatusChanged(sender, val.Value);
        }

        private void ppp_OnConnectionStatusChanged(IO.IDeviceService sender, StateVariableChangedEventArgs<UpnpOrg.WANPPPConnection1.Types.ConnectionStatusValues> e)
        {
            var val = CommonInternetGateway.ToCommonInternetGateway(e.NewValue);

            if (val.HasValue)
                common_OnConnectionStatusChanged(sender, val.Value);
        }

        private void common_OnConnectionStatusChanged(IO.IDeviceService sender, CommonInternetGateway.ConnectionStatusValues e)
        {
            if (!_router.HasValue)
                return;

            // report status change
            if (!_lastConnectionStatus.HasValue || (_lastConnectionStatus != e))
            {
                _db.AddOnlineStatusInfo(
                    _router.Value,
                    new LocalDbConnector.OnlineStatusInfo()
                    {
                        TimeStamp = DateTime.Now,
                        OldStatus = (_lastConnectionStatus.HasValue ? _lastConnectionStatus.Value.ToString() : null),
                        NewStatus = e.ToString()
                    });
            }

            _lastConnectionStatus = e;
        }

        public ConfigDataSlave()
        {
            try
            {
	            _db = new LocalDbConnector();
            }
            catch (Exception ex)
            {
                _log.Error("Failed to connect local database", ex);
            }
        }
    }
}
